<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        
        <meta name="author" content="隐星魂 (Roy.Sun)">
        
        <link rel="shortcut icon" href="../../img/favicon.ico">
        <title>9.电源管理 - 玄武操作系统</title>
        <link href="../../css/bootstrap.min.css" rel="stylesheet">
        <link href="../../css/font-awesome.min.css" rel="stylesheet">
        <link href="../../css/base.css" rel="stylesheet">
        <link rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/10.0.3/styles/color-brewer.min.css">

        <script src="../../js/jquery-1.10.2.min.js" defer></script>
        <script src="../../js/bootstrap.min.js" defer></script>
        <script src="https://cdn.staticfile.org/highlight.js/10.0.3/highlight.min.js"></script>
        <script>hljs.initHighlightingOnLoad();</script> 
    </head>

    <body>
        <div class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
            <div class="container">
                <a class="navbar-brand" href="../..">玄武操作系统</a>
                <!-- Expander button -->
                <button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbar-collapse">
                    <span class="navbar-toggler-icon"></span>
                </button>

                <!-- Expanded navigation -->
                <div id="navbar-collapse" class="navbar-collapse collapse">
                        <!-- Main navigation -->
                        <ul class="nav navbar-nav">
                            <li class="navitem">
                                <a href="../.." class="nav-link">主页</a>
                            </li>
                            <li class="navitem">
                                <a href="../../License/" class="nav-link">开源协议</a>
                            </li>
                            <li class="dropdown">
                                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">快速开发指南 <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">STM32</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../QuickGuide/stm32/01-Envsetup-Guide/" class="dropdown-item">01-开发环境搭建指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/02-atkh743/" class="dropdown-item">02-正点原子阿波罗H743开发板上手指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/03-fk429m/" class="dropdown-item">03-反客F429核心板上手指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/04-atkf103core/" class="dropdown-item">04-正点原子F103核心板上手指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/05-atkf407core/" class="dropdown-item">05-正点原子F407核心板上手指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/06-WeActH750/" class="dropdown-item">06-微行电子H750开发板上手指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/07-Project-From-Scratch-Guide/" class="dropdown-item">07-自定义工程配置指南</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">GD32</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../QuickGuide/gd32/01-Envsetup-Guide/" class="dropdown-item">01-开发环境搭建指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/gd32/02-Project-Setup-Guide/" class="dropdown-item">02-工程配置指南</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">GD32V</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../QuickGuide/gd32v/01-Envsetup-Guide/" class="dropdown-item">01-开发环境搭建指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/gd32v/02-Project-Setup-Guide/" class="dropdown-item">02-工程配置指南</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">NXP S32K</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../QuickGuide/s32k/01-Envsetup-Guide/" class="dropdown-item">01-开发环境搭建指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/s32k/02-Project-Setup-Guide/" class="dropdown-item">02-工程配置指南</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">玄武内核模块</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../QuickGuide/xwko/01-XuanWuKO-Guide/" class="dropdown-item">01-上手指南</a>
</li>
    </ul>
  </li>
                                </ul>
                            </li>
                            <li class="dropdown active">
                                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">应用手册 <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    
<li>
    <a href="../00-Index/" class="dropdown-item">0.目录</a>
</li>
                                    
<li>
    <a href="../01-Brief/" class="dropdown-item">1.简介</a>
</li>
                                    
<li>
    <a href="../02-Basic-System-Architecture/" class="dropdown-item">2.系统基本架构</a>
</li>
                                    
<li>
    <a href="../03-Build-System/" class="dropdown-item">3.构建系统</a>
</li>
                                    
<li>
    <a href="../04-Boot-Flow/" class="dropdown-item">4.启动流程</a>
</li>
                                    
<li>
    <a href="../05-IRQ/" class="dropdown-item">5.中断控制</a>
</li>
                                    
<li>
    <a href="../06-SKD/" class="dropdown-item">6.调度器</a>
</li>
                                    
<li>
    <a href="../07-Thread/" class="dropdown-item">7.线程</a>
</li>
                                    
<li>
    <a href="../08-SWT/" class="dropdown-item">8.软件定时器</a>
</li>
                                    
<li>
    <a href="./" class="dropdown-item active">9.电源管理</a>
</li>
                                    
<li>
    <a href="../10-Lock/" class="dropdown-item">10.锁</a>
</li>
                                    
<li>
    <a href="../11-Sync/" class="dropdown-item">11.同步</a>
</li>
                                    
<li>
    <a href="../12-MM/" class="dropdown-item">12.内存管理</a>
</li>
                                    
<li>
    <a href="../13-C-Lib/" class="dropdown-item">13.玄武C库</a>
</li>
                                </ul>
                            </li>
                            <li class="dropdown">
                                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">Lua手册 <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    
<li>
    <a href="../../LuaManual/00-Index/" class="dropdown-item">0.目录</a>
</li>
                                    
<li>
    <a href="../../LuaManual/01-Brief/" class="dropdown-item">1.简介</a>
</li>
                                    
<li>
    <a href="../../LuaManual/02-XWXT/" class="dropdown-item">2.全局导出表</a>
</li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">3.XWOS内核</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../LuaManual/03-XWOS/01-SDK/" class="dropdown-item">3.1.线程库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/02-Spinlock/" class="dropdown-item">3.2.自旋锁库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/03-Seqlock/" class="dropdown-item">3.3.顺序锁库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/04-Mutex/" class="dropdown-item">3.4.互斥锁库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/05-Semaphore/" class="dropdown-item">3.5.信号量库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/06-Condition/" class="dropdown-item">3.6.条件量库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/07-Flag/" class="dropdown-item">3.7.事件标志库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/08-Barrier/" class="dropdown-item">3.8.线程栅栏库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/09-Selector/" class="dropdown-item">3.9.信号选择器库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/10-PM/" class="dropdown-item">3.10.电源管理</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">4.玄武Lua函数库</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../LuaManual/04-XWLIB/01-Bitmap/" class="dropdown-item">4.1.位图</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">5.设备栈</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../LuaManual/05-XWDS/01-Soc/" class="dropdown-item">5.1.SOC</a>
</li>
            
<li>
    <a href="../../LuaManual/05-XWDS/02-GPIO/" class="dropdown-item">5.2.GPIO</a>
</li>
            
<li>
    <a href="../../LuaManual/05-XWDS/03-UART/" class="dropdown-item">5.3.UART</a>
</li>
            
<li>
    <a href="../../LuaManual/05-XWDS/04-SPI-Master/" class="dropdown-item">5.4.SPI Master</a>
</li>
            
<li>
    <a href="../../LuaManual/05-XWDS/05-IIC-Master/" class="dropdown-item">5.5.IIC Master</a>
</li>
    </ul>
  </li>
                                </ul>
                            </li>
                            <li class="dropdown">
                                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">移植笔记 <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    
<li>
    <a href="../../PortingNote/00-Index/" class="dropdown-item">目录</a>
</li>
                                    
<li>
    <a href="../../PortingNote/01-Porting-Note/" class="dropdown-item">移植笔记</a>
</li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">ARM-Cortex-M</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../PortingNote/02-ARM-Cortex-M/01-ARM-Cortex-M-Porting-Note/" class="dropdown-item">架构移植笔记</a>
</li>
            
<li>
    <a href="../../PortingNote/02-ARM-Cortex-M/02-STM32-Porting-Note/" class="dropdown-item">STM32</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">RISC-V</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../PortingNote/03-RISC-V/01-GD32V-Porting-Note/" class="dropdown-item">GD32V</a>
</li>
    </ul>
  </li>
                                </ul>
                            </li>
                            <li class="dropdown">
                                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">规范 <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    
<li>
    <a href="../../Specification/00-Index/" class="dropdown-item">目录</a>
</li>
                                    
<li>
    <a href="../../Specification/01-Git-Commit-Specification/" class="dropdown-item">git-commit规范</a>
</li>
                                    
<li>
    <a href="../../Specification/02-Version-Branch-Specification/" class="dropdown-item">版本分支规范</a>
</li>
                                </ul>
                            </li>
                        </ul>

                    <ul class="nav navbar-nav ml-auto">
                        <li class="nav-item">
                            <a href="#" class="nav-link" data-toggle="modal" data-target="#mkdocs_search_modal">
                                <i class="fa fa-search"></i> 搜索
                            </a>
                        </li>
                            <li class="nav-item">
                                <a rel="prev" href="../08-SWT/" class="nav-link">
                                    <i class="fa fa-arrow-left"></i> 上一篇
                                </a>
                            </li>
                            <li class="nav-item">
                                <a rel="next" href="../10-Lock/" class="nav-link">
                                    下一篇 <i class="fa fa-arrow-right"></i>
                                </a>
                            </li>
                    </ul>
                </div>
            </div>
        </div>

        <div class="container">
            <div class="row">
                    <div class="col-md-3"><div class="navbar-light navbar-expand-md bs-sidebar hidden-print affix" role="complementary">
    <div class="navbar-header">
        <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#toc-collapse" title="Table of Contents">
            <span class="fa fa-angle-down"></span>
        </button>
    </div>

    
    <div id="toc-collapse" class="navbar-collapse collapse card bg-secondary">
        <ul class="nav flex-column">
            
            <li class="nav-item" data-level="1"><a href="#9" class="nav-link">9.电源管理</a>
              <ul class="nav flex-column">
            <li class="nav-item" data-level="2"><a href="#91" class="nav-link">9.1.描述</a>
              <ul class="nav flex-column">
              </ul>
            </li>
            <li class="nav-item" data-level="2"><a href="#92mp" class="nav-link">9.2.MP系统的电源管理</a>
              <ul class="nav flex-column">
              </ul>
            </li>
            <li class="nav-item" data-level="2"><a href="#93up" class="nav-link">9.3.UP内核的电源管理</a>
              <ul class="nav flex-column">
              </ul>
            </li>
            <li class="nav-item" data-level="2"><a href="#94" class="nav-link">9.4.配置</a>
              <ul class="nav flex-column">
              </ul>
            </li>
            <li class="nav-item" data-level="2"><a href="#95api" class="nav-link">9.5.API参考</a>
              <ul class="nav flex-column">
              </ul>
            </li>
            <li class="nav-item" data-level="2"><a href="#96" class="nav-link">9.6.附录</a>
              <ul class="nav flex-column">
              </ul>
            </li>
              </ul>
            </li>
        </ul>
    </div>
</div></div>
                    <div class="col-md-9" role="main">

<h1 id="9">9.电源管理</h1>
<h2 id="91">9.1.描述</h2>
<p>玄武OS有两套电源管理框架，分别用于MP系统和UP系统。</p>
<p>玄武OS的电源管理框架只提供了基本流程，最终SOC如何休眠由BSP中的回调函数实现：
用户可以自行决定是否保持SDRAM的刷新、是否保持某些GPIO的输出、或则是否进入最低功耗的待机等等。</p>
<h2 id="92mp">9.2.MP系统的电源管理</h2>
<h3 id="_1">电源管理领域</h3>
<p>MP系统中，CPU不只一个，玄武OS中使用<strong>电源管理领域</strong>(<strong>PMDM</strong>)来统一管理所有CPU的休眠与唤醒。</p>
<h3 id="_2">流程</h3>
<p><img alt="img" src="../res/figure/mp-pm-flow.png" title="MP系统电源管理流程" /></p>
<p>图中，左列为休眠流程，右列为唤醒流程，箭头代表了可以进行<strong>电源管理阶段</strong>转换的方向。
<strong>电源管理领域</strong>将电源管理分为四个阶段（图中绿色的框）：</p>
<h5 id="xwmp_pmdm_stage_running">正在运行 (<code>XWMP_PMDM_STAGE_RUNNING</code>)</h5>
<p>所有CPU正常运行，可以使用下面API进入休眠的流程：</p>
<pre><code class="C">xwer_t xwos_pm_suspend(void);
</code></pre>

<h5 id="xwmp_pmdm_stage_freezing-xwmp_pmdm_stage_thawing">冻结调度器 —— 解冻调度器 (<code>XWMP_PMDM_STAGE_FREEZING - XWMP_PMDM_STAGE_THAWING</code>)</h5>
<p>一旦开始休眠流程，PMDM会通知所有CPU冻结线程。当调度器中线程
全部冻结后，调度器会向PMDM报告<strong>已经暂停</strong>的状态。调度器冻结
线程的过程是一个比较复杂的过程，这个阶段又分为几个子阶段（图中蓝色的框）：</p>
<h6 id="xwmp_skd_wklkcnt_freezing-xwmp_skd_wklkcnt_thawing"># 冻结线程 —— 解冻线程 (<code>XWMP_SKD_WKLKCNT_FREEZING - XWMP_SKD_WKLKCNT_THAWING</code>)</h6>
<p>调度器会中断所有线程的<strong>等待</strong>和<strong>睡眠</strong>态，并为所有线程设置<strong>可冻结</strong>标志，
然后依次调度每个线程，直到它们运行到<strong>冻结点</strong>进行冻结，这个过程耗时比较长，
在执行过程中如果遇到唤醒事件，调度器会在唤醒事件中断中切换为解冻流程：
解冻已经冻结的线程，并取消未冻结的线程的<strong>可冻结</strong>标志。</p>
<h6 id="xwmp_skd_wklkcnt_allfrz"># 全部线程已经冻结 (<code>XWMP_SKD_WKLKCNT_ALLFRZ</code>)</h6>
<p>最后一个线程完成冻结时，CPU处于调度器服务中断中，调度器会将滴答定时器关闭。
如果此刻出现唤醒事件，待CPU从调度器服务中断中退出后，会立即进入唤醒事件中断。
休眠流程切换为唤醒流程，并重新打开滴答定时器。
按照<a href="../06-SKD/#SKD-IRQ">调度器的中断</a>的描述，唤醒事件中断的优先级是低于
调度器服务中断的，因此唤醒事件中断一定会在调度器服务中断退出后才开始执行，
因此滴答定时器一定会先关闭，然后再打开，顺序不会错乱。</p>
<h6 id="xwmp_skd_wklkcnt_suspended"># 调度器已经暂停 (<code>XWMP_SKD_WKLKCNT_SUSPENDED</code>)</h6>
<p>CPU从上一步骤的调度器服务中断中退出后，会切换回线程上下文，此时因所有
线程已经冻结，CPU只可能运行在<a href="../06-SKD/#SKD-IDLE-TASK">空闲任务</a>中。
CPU会在空闲任务中向PMDM报告调度器<strong>已经暂停</strong>的状态。此过程不能在调度器服务中断
中进行，因为调度器服务中断是最高优先级中断，不能被唤醒事件中断打断，
有可能会导致无法唤醒的问题。</p>
<h5 id="xwmp_pmdm_stage_suspending-xwmp_pmdm_stage_resuming">正在暂停 —— 正在恢复 (<code>XWMP_PMDM_STAGE_SUSPENDING - XWMP_PMDM_STAGE_RESUMING</code>)</h5>
<p>当最后一个CPU报告了<strong>已经暂停</strong>的状态后，会在最后一个CPU的<strong>空闲任务</strong>中执行用户
的<code>suspend()</code>回调函数。此时，如果出现唤醒事件，电源管理的阶段会从<strong>正在暂停</strong>切换
为<strong>正在恢复</strong>，并执行用户的<code>resume()</code>回调函数。</p>
<ul>
<li><code>suspend()</code>回调函数用于在休眠之前让用户关闭设备、配置SDRAM刷新模式、配置GPIO等；</li>
<li><code>resume()</code>回调函数用于在唤醒之前执行与<code>suspend()</code>回调函数相反的操作；</li>
<li>执行这两个函数时，PMDM会自动锁定<strong>resume-suspend锁</strong>，并关闭当前
    CPU的总中断开关。<strong>resume-suspend锁</strong>是自旋锁，如果CPU-1正在
    执行<code>suspend()</code>回调函数，此时出现了唤醒事件，会分下面两种情况进行处理：<ul>
<li>唤醒事件中断也绑定在CPU-1上，唤醒事件中断会挂起，直到<code>suspend()</code>回调函数
    返回，PMDM解锁<strong>resume-suspend锁</strong>并打开CPU总中断开关，才被处理，
    然后执行<code>resume()</code>回调函数；</li>
<li>唤醒事件中断绑定在CPU-2上，CPU-2会立即进入唤醒事件中断，但一直会
    <strong>自旋</strong>等待CPU-1释放<strong>resume-suspend锁</strong>，直到获得<strong>resume-suspend锁</strong>后，
    才会执行<code>resume()</code>回调函数；</li>
</ul>
</li>
<li>示例STM32F429的<code>resume()</code>与<code>suspend()</code>回调函数：</li>
</ul>
<p><a id="PM-RESUME-SUSPEND"></a></p>
<pre><code class="C">/* xwbd/fk429m/bm/stm32cube/xwds/pm.c */
void stm32cube_pm_resume(void)
{
        __maybe_unused xwer_t rc;
        xwirq_t irq;

        rc = xwos_irq_get_id(&amp;irq); /* 获取此时的中断号，用于调试 */

        /* 恢复默认值 */
        LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_MAINREGU);

        /* 恢复stm32cube中的所有设备 */
        xwds_pm_resume(&amp;stm32cube_ds);
}

void stm32cube_pm_suspend(void)
{
        __maybe_unused xwer_t rc;
        xwirq_t irq;

        rc = xwos_irq_get_id(&amp;irq); /* 获取此时的中断号，用于调试 */

        /* 暂停stm32cube：
           + 暂停所有设备
           + 配置GPIO
           + 配置SDRAM的自刷新模式 */
        xwds_pm_suspend(&amp;stm32cube_ds);

        /* 设置休眠方式为STOP模式并开启低功耗调压器。
           STM32的STOP模式下寄存器与内部RAM数据不丢失，
           外部SDRAM因配置了自动刷新模式也不会丢失，
           因此休眠方式为SuspendToRAM，唤醒后运行状态可恢复。*/
        LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_LPREGU);

        /* 设置ARMv7-m的DEEPSLEEP位 */
        LL_LPM_EnableDeepSleep();
}
</code></pre>

<h5 id="xwmp_pmdm_stage_suspended">已经暂停 (<code>XWMP_PMDM_STAGE_SUSPENDED</code>)</h5>
<p>此阶段为休眠流程的最后一个阶段，也是唤醒流程的第一个阶段。
此阶段提供给用户的回调函数：</p>
<ul>
<li><code>sleep()</code>：休眠SOC</li>
<li><code>wakeup()</code>：唤醒SOC</li>
</ul>
<p>当最后一个CPU的<strong>空闲任务</strong>执行完上一阶段的<code>suspend()</code>回调函数后，
PMDM将电源管理步骤切换到此阶段，并执行<code>sleep()</code>回调函数。
SOC系统在<code>sleep()</code>回调函数内部进入低功耗状态，
此时时钟停止，代码停止运行，<code>sleep()</code>回调函数不会返回。</p>
<p>玄武OS将<code>sleep()</code>回调函数设计在空闲任务中执行，是因为中断优先级的问题有可能
导致系统无法唤醒。例如基于ARM-m的单片机，如果在一个高优先级的中断中执行了
休眠指令（<code>wfi</code>），低优先级的唤醒中断无法把系统唤醒。</p>
<p>当唤醒事件出现，<strong>wakeup()</strong>回调函数在唤醒事件中断中执行。</p>
<p>回调函数<code>sleep()</code>与<code>wakeup()</code>之间没有锁的保护，
因此<code>sleep()</code>回调函数需要设计成能被<code>wakeup()</code>回调函数打断。</p>
<p>示例，STM32F429的<code>wakeup()</code>与<code>sleep()</code>回调函数：
<a id="PM-WAKEUP-SLEEP"></a></p>
<pre><code class="C">/* xwbd/fk429m/bm/stm32cube/xwds/pm.c */
void stm32cube_pm_wakeup(void)
{
        LL_LPM_EnableSleep(); /* 清除DEEPSLEEP位 */
        SystemClock_Config(); /* 重新配置时钟 */
}

void stm32cube_pm_sleep(void)
{
        /* 位置1 */
        wfi();
        /* 位置2 */
}
</code></pre>

<p>分为两种情况讨论：</p>
<ul>
<li><code>stm32cube_pm_sleep()</code>中的<code>WFI</code>指令执行后出现唤醒事件：
    唤醒流程执行完毕后，代码会回到<code>stm32cube_pm_sleep()</code>中<strong>位置2</strong>；</li>
<li><code>stm32cube_pm_sleep()</code>中的<code>WFI</code>指令执行之前出现唤醒事件：
    唤醒事件中断会打断<code>stm32cube_pm_sleep()</code>函数，然后
    执行<code>stm32cube_pm_wakeup()</code>函数，<code>LL_LPM_EnableSleep()</code>
    会清除ARMv7-m的DEEPSLEEP位，接下来的唤醒流程也会将滴答定时器重新打开，当
    再次回到<code>stm32cube_pm_sleep()</code>的<strong>位置1</strong>时，<code>WFI</code>指令只会使CPU进入
    ARMv7-m的SLEEP模式，这种模式只是暂停了CPU时钟，即将到来的滴答定时器中断
    可使系统恢复正常。</li>
</ul>
<h2 id="93up">9.3.UP内核的电源管理</h2>
<h3 id="_3">流程</h3>
<p><img alt="img" src="../res/figure/up-pm-flow.png" title="UP系统电源管理流程" /></p>
<p>图中，左列为休眠流程，右列为唤醒流程，箭头代表了<strong>电源管理阶段</strong>切换的方向。
UP系统电源管理分为五个阶段：</p>
<h5 id="xwup_pm_stage_running">正在运行 (<code>XWUP_PM_STAGE_RUNNING</code>)</h5>
<p>调度器正常运行，可以使用下面API进入休眠的流程：</p>
<pre><code class="C">xwer_t xwup_skd_suspend(void);
</code></pre>

<h5 id="xwup_pm_stage_freezing-xwup_pm_stage_thawing">正在冻结线程 —— 正在解冻线程 (<code>XWUP_PM_STAGE_FREEZING - XWUP_PM_STAGE_THAWING</code>)</h5>
<p>一旦开始休眠流程，调度器会中断所有线程的<strong>等待</strong>和<strong>睡眠</strong>态，并通知所有线程冻结。
这个过程耗时比较长，在执行过程中如果遇到唤醒事件，调度器可在唤醒事件中断中
切换为解冻流程：解冻已冻结的线程，并将调度器状态逐步恢复至<strong>正在运行</strong>。</p>
<h5 id="xwup_pm_stage_allfrz">调度器中全部线程已经冻结 (<code>XWUP_PM_STAGE_ALLFRZ</code>)</h5>
<p>最后一个线程完成冻结时，CPU处于调度器服务中断中，调度器会将滴答定时器关闭。
如果此刻出现唤醒事件，待CPU从调度器服务中断中退出后，会立即进入唤醒事件中断，
休眠流程切换为唤醒流程，并重新打开滴答定时器。
按照<a href="../06-SKD/#SKD-IRQ">调度器的中断</a>的描述，唤醒事件中断的优先级
是低于调度器服务中断的，因此唤醒事件中断一定会在调度器服务中断退出
后才开始执行，滴答定时器一定会先关闭，然后再打开，顺序不会错乱。</p>
<h5 id="xwup_pm_stage_suspending-xwup_pm_stage_resuming">正在暂停 —— 正在恢复 (<code>XWUP_PM_STAGE_SUSPENDING - XWUP_PM_STAGE_RESUMING</code>)</h5>
<p>当全部线程冻结后，调度器只能调度<strong>空闲任务</strong>，调度器会在<strong>空闲任务</strong>中执行用户
的<code>suspend()</code>回调函数。此时，如果出现唤醒事件，系统会在唤醒事件中断中将状态从
<strong>正在暂停</strong>切换为<strong>正在恢复</strong>，并执行用户的<code>resume()</code>回调函数。</p>
<ul>
<li><code>suspend()</code>回调函数用于在休眠之前让用户关闭设备、配置SDRAM刷新模式、配置GPIO等；</li>
<li><code>resume()</code>回调函数用于在唤醒之前执行与<code>suspend()</code>回调函数相反的操作；</li>
<li>执行这两个函数时系统会关闭CPU总中断开关。如果正在执行<code>suspend()</code>回调函数时
    出现了唤醒事件，唤醒事件中断会挂起，直到<code>suspend()</code>回调函数，系统
    打开CPU总中断开关时才被处理，然后执行<code>resume()</code>回调函数；</li>
<li>示例：<a href="#PM-RESUME-SUSPEND">STM32F429的<code>resume()</code>与<code>suspend()</code>回调函数</a></li>
</ul>
<h5 id="xwup_pm_stage_suspended">已经暂停 (<code>XWUP_PM_STAGE_SUSPENDED</code>)</h5>
<p>此阶段为休眠流程的最后一个阶段，也是唤醒流程的第一个阶段。
此阶段提供给用户的回调函数：</p>
<ul>
<li><code>sleep()</code>：休眠SOC</li>
<li><code>wakeup()</code>：唤醒SOC</li>
</ul>
<p>当<strong>空闲任务</strong>执行完上一阶段的<code>suspend()</code>回调函数后，
电源管理步骤切换到此阶段，并执行<code>sleep()</code>回调函数。SOC系统在<code>sleep()</code>回调函数
内部进入休眠状态，此时时钟停止，代码停止运行，<code>sleep()</code>回调函数不会返回。</p>
<p>玄武OS将<code>sleep()</code>回调函数设计在空闲任务中执行，是因为中断优先级的问题有可能
导致系统无法唤醒。例如基于ARM-m的单片机，如果在一个高优先级的中断中执行了
休眠指令（<code>WFI</code>），低优先级的唤醒中断无法把系统唤醒。</p>
<p>当唤醒事件出现，<code>wakeup()</code>回调函数在唤醒事件中断中执行。</p>
<p>回调函数<code>sleep()</code>与<code>wakeup()</code>之间没有锁的保护，
因此<code>sleep()</code>回调函数需要设计成能被<code>wakeup()</code>回调函数打断。</p>
<p>示例：<a href="#PM-WAKEUP-SLEEP">STM32F429的<code>wakeup()</code>与<code>sleep()</code>回调函数</a></p>
<h2 id="94">9.4.配置</h2>
<h5 id="cfgxwosh">cfg/xwos.h</h5>
<ul>
<li>MP内核配置：<ul>
<li>（空）</li>
</ul>
</li>
<li>UP内核配置：<ul>
<li>调度器<ul>
<li><code>XWUPCFG_SKD_PM</code>：是否启用电源管理，取值：1|0；</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="95api">9.5.API参考</h2>
<ul>
<li>头文件：<code>xwos/osal/pm.h</code></li>
<li>注释：见头文件</li>
</ul>
<h2 id="96">9.6.附录</h2>
<ul>
<li><a href="../00-Index/">返回目录</a></li>
</ul></div>
            </div>
        </div>

        <footer class="col-md-12">
            <hr>
            <p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
        </footer>
        <script>
            var base_url = "../..",
                shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
        </script>
        <script src="../../js/base.js" defer></script>
        <script src="../../search/main.js" defer></script>

        <div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title" id="searchModalLabel">搜索</h4>
                <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
            </div>
            <div class="modal-body">
                <p>
                    在这里所有文档：
                </p>
                <form>
                    <div class="form-group">
                        <input type="search" class="form-control" placeholder="搜索..." id="mkdocs-search-query" title="Type search term here">
                    </div>
                </form>
                <div id="mkdocs-search-results"></div>
            </div>
            <div class="modal-footer">
            </div>
        </div>
    </div>
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="keyboardModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title" id="keyboardModalLabel">Keyboard Shortcuts</h4>
                <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
            </div>
            <div class="modal-body">
              <table class="table">
                <thead>
                  <tr>
                    <th style="width: 20%;">Keys</th>
                    <th>Action</th>
                  </tr>
                </thead>
                <tbody>
                  <tr>
                    <td class="help shortcut"><kbd>?</kbd></td>
                    <td>Open this help</td>
                  </tr>
                  <tr>
                    <td class="next shortcut"><kbd>n</kbd></td>
                    <td>Next page</td>
                  </tr>
                  <tr>
                    <td class="prev shortcut"><kbd>p</kbd></td>
                    <td>Previous page</td>
                  </tr>
                  <tr>
                    <td class="search shortcut"><kbd>s</kbd></td>
                    <td>Search</td>
                  </tr>
                </tbody>
              </table>
            </div>
            <div class="modal-footer">
            </div>
        </div>
    </div>
</div>

    </body>
</html>
